package com.demo.spring.security.security;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.demo.spring.security.entity.*;
import com.demo.spring.security.mapper.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public interface SecurityService extends UserDetailsService {

    String encodePassword(String rawPassword);
    boolean checkPassword(CharSequence rawPassword, String encodedPassword);

    /**
     * 默认实现
     */
    @Slf4j
    @Service
    @RequiredArgsConstructor(onConstructor=@__({@Autowired,@Lazy}))
    class Default implements SecurityService{

        private final CusUserMapper cusUserMapper;
        private final CusRoleMapper cusRoleMapper;
        private final CusRoleUserMapper cusRoleUserMapper;
        private final CusPrmsRoleMapper cusPrmsRoleMapper;
        private final CusPrmsUserMapper cusPrmsUserMapper;
        private final PasswordEncoder passwordEncoder;

        /**
         * 用户名密码登录，通过用户名加载UserDetails
         */
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            CusUser cusUser = cusUserMapper.selectOne(new LambdaQueryWrapper<CusUser>().eq(CusUser::getUsername,username));
            if(cusUser ==null){
                log.warn("登录用户[{}]不存在。",username);
                throw new UsernameNotFoundException(String.format("登录用户[%s]不存在",username));
            }
            List<CusRoleUser> cusRoleUserList = cusRoleUserMapper.listByUserId(cusUser.getId());
            List<CusPrmsUser> cusPrmsUserList = cusPrmsUserMapper.listByUserId(cusUser.getId());
            Set<String> wfPrmsCodeSet = new HashSet<>(32);
            cusRoleUserList.forEach(cusRoleUser -> {
                CusRole cusRole = cusRoleUser.getRole();
                if(cusRole!=null){
                    wfPrmsCodeSet.add("ROLE_"+cusRole.getCode());
                    List<CusPrmsRole> cusPrmsRoleList = cusRole.getPrmsRoleList();
                    if(cusPrmsRoleList!=null){
                        cusPrmsRoleList.forEach(cusPrmsRole -> {
                            CusPrms cusPrms = cusPrmsRole.getPrms();
                            if(cusPrms!=null){
                                if(Boolean.TRUE.equals(cusPrmsRole.getDisabled())){
                                    wfPrmsCodeSet.remove(cusPrms.getCode());
                                }else{
                                    wfPrmsCodeSet.add(cusPrms.getCode());
                                }
                            }
                        });
                    }
                }
            });
            cusPrmsUserList.forEach(cusPrmsUser -> {
                CusPrms cusPrms = cusPrmsUser.getPrms();
                if(cusPrms!=null){
                    if(Boolean.TRUE.equals(cusPrmsUser.getDisabled())){
                        wfPrmsCodeSet.remove(cusPrms.getCode());
                    }else{
                        wfPrmsCodeSet.add(cusPrms.getCode());
                    }
                }
            });
            Set<SimpleGrantedAuthority> authorities = wfPrmsCodeSet.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
            return new User(cusUser.getUsername(), cusUser.getPassword(),authorities);
        }

        /**
         * 密码加密
         * @param rawPassword 明文密码
         * @return 加密密码
         */
        @Override
        public String encodePassword(String rawPassword) {
            return passwordEncoder.encode(rawPassword);
        }

        /**
         * 密码校验
         * @param rawPassword 明文密码
         * @param encodedPassword 加密密码
         * @return 校验结果
         */
        @Override
        public boolean checkPassword(CharSequence rawPassword, String encodedPassword) {
            return passwordEncoder.matches(rawPassword,encodedPassword);
        }

    }

}
